<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.4.1 / SVN信息: $Id: class.JCAT_Global.php 1510 2009-03-23 06:51:00Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/


/**
 * 全局函数集
 *
 * @author		alee
 * @access		public
 * @last		2007.12.6
 */
class JCAT_Global
{


	/**
	 * 结构化输出 一个变量
	 * 
	 * @access	public
	 * @param	$Var				mixed	输出的变量
	 * @param	$bOutAtOnce=true	bool	是否立即输出
	 * @static
	 * @return	string
	 */
	static public function PrintVar(  $Var,  $bOutAtOnce=true ) 
	{
		// 特殊值
		if($Var===false)
		{
			$Var = 'false' ;
		}
		else if($Var===true)
		{
			$Var = 'true' ;
		}
		else if($Var===null)
		{
			$Var = 'null' ;
		}

		$sOut = print_r($Var,true) ;
		
		if( $bOutAtOnce )
		{
			print $sOut ;
		}

		return $sOut ;
	}
	
	
	/**
	 * 测试执行流程的函数
	 *   如果 t() 没有给参数，则简单 输出/返回  t() 的调用次数 ；
	 *   如果 传入参数，则依次调用  JCAT_Global::PrintVar() 输出所传入的参数
	 *
	 * @access	public
	 * @static
	 * @return	int
	 */
	static public function t()
	{
		
		// 无参数
		if( func_num_args()==0 )
		{
			static $__oOtlaaltOo__ = 0;
			self::t( 't(): '.++$__oOtlaaltOo__ ) ;
			return $__oOtlaaltOo__ ;
		}
		
		// 输出参数
		$arrArgv = func_get_args() ;
		$sOut = '' ;
		foreach ($arrArgv as $Item)
		{
			$sItem = '<pre>' ;
			$sItem.= self::PrintVar($Item) ;
			$sItem.= "</pre>\r\n" ;
			
			print $sItem ;
			
			$sOut.= $sItem ;
		}
		
		// 释放输出缓存
		flush();
		return $sOut ;
	}



	/**
	 * 递归地检查给定的两个类(接口)之间的 继承 关系。
	 * 如果 参数 $SubClass 和 $sBaseClass 相同，仍然返回 true ，表示 “IsKindOf” 关系成立。
	 * 如果 $SubClass 或 $sBaseClass 传入不存在的类名，简单的返回 false ，而不会抛出异常，或进行更严重的错误处理。
	 * php 的原生函数 is_subclass_of() 只对 直接继承提供判断，本函数是对  is_subclass_of() 的加强。
	 * 注：is_subclass_of() 在判断直接继承时，仍然有用。
	 *
	 * @access	public
	 * @param	$SubClassOrInstance	string,object	子类，或 子类的一个实例
	 * @param	$sBaseClass			string			父类
	 * @return	bool
	 */
	static public function IsKindOf(  $SubClassOrInstance,  $sBaseClass ) 
	{
		// 接口
		if( JCAT_Package::ClassExists($sBaseClass,true) )
		{
			return self::HasImplementedTo($SubClassOrInstance,$sBaseClass) ;
		}

		// 类
		else
		{
			// 统一类名
			if( is_object($SubClassOrInstance) )
			{
				$sSubClassOrInstanceName = get_class($SubClassOrInstance) ;
			}
			elseif( is_string($SubClassOrInstance) )
			{
				$sSubClassOrInstanceName = $SubClassOrInstance ;
			}
			else
			{
				return false ;
			}
			
			// 子类名 即为  父类名
			if( $sSubClassOrInstanceName==$sBaseClass )
			{
				return true ;
			}
			
			// 递归检查
			$sParentClass = get_parent_class($sSubClassOrInstanceName) ;
			if(!$sParentClass)
			{
				return false ;
			}

			return self::IsKindOf($sParentClass,$sBaseClass) ;
		}
	}



	/**
	 * 检查一个 类或对象 是否实现了某个接口
	 *
	 * 
	 * @access	public
	 * @param	$ClassOrObject		string,object	待检查的类或对象
	 * @param	$sInterface			string			应实现的接口名
	 * @param	$bStrictly=false	bool			是否严格检查 所有 的 接口的所有方法均已实现（非抽象方法）
	 * @return	bool
	 */
	static public function HasImplementedTo(  $ClassOrObject,  $sInterface,  $bStrictly=false ) 
	{
		if( is_object($ClassOrObject) )
		{
			$sClassName = get_class($ClassOrObject) ;
		}
		elseif( is_string($ClassOrObject) )
		{
			$sClassName = $ClassOrObject ;
		}
		else
		{
			return false ;
		}
		
		// 类型检查
		if( !is_string($sClassName) )
		{
			return false ;
			//throw new JCAT_Exception("参数 \$ClassOrObject({$sClassName}) 必须是一个 类名(sting) 或 对象",JCAT_Exception::MakeExceptionCode(__CLASS__,2)) ;
		}
		
		// 检查 类 和 接口 是否都有效
		if( !class_exists($sClassName) or !interface_exists($sInterface) )
		{
			return false ;
			//throw new JCAT_Exception("参数 \$ClassOrObject({$sClassName}) 和 \$sInterface({$sInterface}) 必须是已定义的对象和接口。",JCAT_Exception::MakeExceptionCode(__CLASS__,3)) ;
		}

		$aReflectionClass = new ReflectionClass( $sClassName ) ;
		$arrInterfaceRefs = $aReflectionClass->getInterfaces() ;
		foreach($arrInterfaceRefs as $aInterfaceRef)
		{
			if( $aInterfaceRef->getName()!=$sInterface )
			{
				continue ;
			}


			// 找到 匹配的 接口 ========================
			if(!$bStrictly)
			{
				return true ;
			}

			// 依次检查 接口中的每个方式， 是否实现
			$arrInterfaceFuncs = get_class_methods($sInterface) ;
			foreach ($arrInterfaceFuncs as $sFuncName)
			{
				$aReflectionMethod = $aReflectionClass->getMethod($sFuncName) ;
				// 发现 尚为抽象 的方法
				if( $aReflectionMethod->isAbstract() )	
				{
					return false ;
				}
			}
			return true ;
			// ======================================
		}


		// 递归检查父类
		if( $sParentName=get_parent_class($sClassName) )
		{
			return self::HasImplementedTo( $sParentName,$sInterface,$bStrictly ) ;
		}
		else
		{
			return false ;
		}
	}



	/**
	 * 将一个数组整理成 url的query 部分
	 * 
	 * @access	public
	 * @param	$arrVar			array	待整理的数组变量
	 * @param	$sVarName=null	string	数组变量的名称
	 * @static
	 * @return	string
	 */
	static public function Array2UrlQeruy(  array $arrVar,  $sVarName=null ) 
	{
		$arrRet = array() ;
		foreach ($arrVar as $sKey=>$Item)
		{
			if($sVarName===null)
			{
				$sKeyName = $sKey ;
			}
			else
			{
				$sKeyName = $sVarName."%5B{$sKey}%5D" ;
			}
			
			if( is_scalar($Item) )
			{
				$arrRet[] = $sKeyName.'='.urlencode($Item) ;
			}
				
			elseif( is_array($Item) )
			{
				$arrRet[] = self::Array2UrlQeruy($Item,$sKeyName) ;
			}
		}
		
		return implode('&',$arrRet) ;
	}
	
	
	/**
	 * 将当前请求的Request参数 整理成一个可用于 url 的字串返回
	 * 
	 * @access	public
	 * @param	$bPost=false			bool
	 * @static
	 * @return	string
	 */
	static public function Request2UrlQeruy($bPost=false) 
	{
		$sRet = JCAT_Global::Array2UrlQeruy( $_GET ) ;
		
		if($bPost)
		{
			$sPostQuery = JCAT_Global::Array2UrlQeruy( $_POST ) ;
			if($sPostQuery)
			{
				$sRet.= $sPostQuery ;
			}
		}
		
		return $sRet ;
	}
	
	/**
	 * 检查是否为同一个 callback
	 *
	 * @access	public
	 * @param	$CallbackA		callback
	 * @param	$CallbackB		callback
	 * @static
	 * @return	bool
	 */
	static public function IsSameCallback($CallbackA,$CallbackB)
	{
		JCAT_ASSERT::ASSERT_ISTHESE($CallbackA,array('callback')) ;
		JCAT_ASSERT::ASSERT_ISTHESE($CallbackB,array('callback')) ;
		
		
		if( is_array($CallbackA) )
		{
			if( is_array($CallbackB) )
			{
				return ($CallbackA[0]===$CallbackB[0])
					and ( strtolower($CallbackA[1])===strtolower($CallbackB[1]) ) ;
			}
			
			else 
			{
				return false ;
			}
		}
		
		else
		{
			return strtolower($CallbackA) === strtolower($CallbackB) ;
		}
	}
	
	/**
	 * 格式化输出
	 * 根据项目类型（CommandLine,Desktop,Html） 和  服务器字符集 整理输出内容
	 * 
	 * @access	public
	 * @param	$Content	mixed	输出内容
	 * @static
	 * @return	string
	 */
	static public function FormatOut($Content)
	{
		// 留待处理 ... ...
		$sContent = print_r($Content,true) ;
		
		switch( JCAT::$TYPE )
		{
			case JCAT::TYPE_HTML :
				print '<pre>'.$sContent.'</pre>' ;
				break ;
			
			case JCAT::TYPE_COMMANDLINE :
				print JCAT::CharsetToServer($sContent) ;
				break ;
			
			case JCAT::TYPE_DESKTOP :
				print JCAT::CharsetToServer($sContent) ;
				break ;
			
			default :
				JCAT_ASSERT::ASSERT_(0,'?!') ;
				break ;
		}
		
	}
	
	
	/**
	 * JCAT_Global::FormatOut() 的别名
	 * 
	 * @access	public
	 * @param	$Content	mixed	输出内容
	 * @static
	 * @return	string
	 */
	static public function FO($Content)
	{ return self::FormatOut($Content) ; }
	
	
	/**
	 * 为函数或 类的静态方法取一个别名
	 * 
	 * @access	public
	 * @param	$sAlias				string		函数的新别名
	 * @param	$OriginalFunction	callback	函数
	 * @static
	 * @return	void
	 */
	static public function MakeFunctionAlias($sAlias,$OriginalFunction)
	{
		if( is_callable($OriginalFunction) )
		{
			if( function_exists($sAlias) )
			{
				throw new JCAT_Exception("同名的全局函数：“$sAlias”已经定义！",JCAT_Exception::MakeExceptionCode(__CLASS__,4)) ;
			}
			
			// 整理 原函数名
			if( is_array($OriginalFunction) )
			{
				if( is_object($OriginalFunction[0]) )
				{
					throw new JCAT_Exception('参数 $OriginalFunction 只能是 全局函数或类的静态方法',JCAT_Exception::MakeExceptionCode(__CLASS__,5)) ;
				}
				
				$OriginalFunction = "array('{$OriginalFunction[0]}','{$OriginalFunction[1]}')" ;
			}
			else
				$OriginalFunction = "'{$OriginalFunction}'" ;
			
			// 创建别名函数
			eval("function {$sAlias}(){ \$arrArgvs = func_get_args(); \$Ret = call_user_func_array({$OriginalFunction} ,\$arrArgvs); return \$Ret; }") ;
		}
		else
		{
			throw new JCAT_Exception('参数 $OriginalFunction 未定义，$OriginalFunction 必须是一个已定义的函数或类的静态方法。',JCAT_Exception::MakeExceptionCode(__CLASS__,6)) ;		
		}
	}
	
	/**
	 * 为已定义的类取一个别名
	 * 
	 * @access	public
	 * @param	$sAlias			string	类的新别名
	 * @param	$sOriginalClass	string	原始类名
	 * @static
	 * @return	void
	 */
	static public function MakeClassAlias($sAlias,$sOriginalClass)
	{echo ',' ;
		if( !class_exists($sOriginalClass) )
		{
			throw new JCAT_Exception("类 {$sOriginalClass} 尚未定义，无法为不存在的类创建别名。",JCAT_Exception::MakeExceptionCode(__CLASS__,7)) ;
		}
		if( class_exists($sAlias) )
		{
			throw new JCAT_Exception("名为 {$sAlias} 的类已经存在，无法用作别名。",JCAT_Exception::MakeExceptionCode(__CLASS__,8)) ;
		}

		eval("class {$sAlias} extends {$sOriginalClass}{}") ;
	}
	
	
	
	
	/**
	 * 判断变量的类型
	 * PHP的原生函数is_a()只判断对象，JCAT_Global::IsA() 将所有类型和类(class) 同等看待
	 * 如果类型 是 类名，则以 is_a（IsKindOf()函数） 判断
	 * 
	 * @access	public
	 * @param	$Variable	mixed	待检查的变量名
	 * @param	$sType		string	类型
	 * @static
	 * @return	void
	 */
	static public function IsA($Variable,$sType)
	{
		JCAT_ASSERT::ASSERT_STRING($sType) ;
		
		// 整理参数， 以支持  array:xxx 格式 
		$sType = trim($sType) ;
		$arrTypes = explode(':',$sType) ;
		$sRealType = $arrTypes[0] ;
		$sAllow = isset($arrTypes[1])? $arrTypes[1]: null ;
		
		$sRealType = strtolower($sRealType) ;
		
		switch( $sRealType )
		{
			// 字符串
			case 'string' :
				return is_string($Variable) ;
			
			// 整数
			case 'integer' :
			case 'int' :
				return is_int($Variable) ;
				
			// 浮点
			case 'float' :
				return is_float($Variable) ;
				
			// 布尔
			case 'boolean' :
			case 'bool' :
				return is_bool($Variable) ;
				
			// 数字
			case 'num' :
			case 'numeric' :
				return is_numeric($Variable) ;
			
			// 标量（所有基础类型）
			case 'base' :
			case 'scalar' :
				return is_scalar($Variable) ;
			
			// 外部资源
			case 'handle' :
			case 'resource' :
				return is_resource($Variable) ;
			
			// 数组
			case 'array' :
			{
				if( $sAllow )
				{
					$arrAllow = explode(',',$sAllow) ;//print_R($arrAllow) ;
					return self::CheckArray($Variable,$arrAllow) ;
				}
				else
					return is_array($Variable) ;
			}
			
			// 对象
			case 'object' :
				return is_object($Variable) ;
				
			// 空
			case 'null' :
			case 'NULL' :
				return ($Variable===null) ;
			
			// 回调函数
			case 'callback' :
				return is_callable($Variable) ;
			
			// 类
			default :
				return self::IsKindOf($Variable,$sType) ;
		}
	}
	
	/**
	 * 返回变量的类型
	 *
	 * @access	public
	 * @param	$Variable
	 * @static
	 * @return	string
	 */
	static public function GetClass($Variable)
	{
		if( is_object($Variable) )
		{
			return get_class($Variable) ;
		}
		
		else if ( is_array($Variable) )
		{
			return 'array' ;
		}
		
		else if ( is_string($Variable) )
		{
			return 'string' ;
		}
		
		else if ( is_numeric($Variable) )
		{
			return 'number' ;
		}
		
		else if ( is_bool($Variable) )
		{
			return 'bool' ;
		}
		
		else if ( is_resource($Variable) )
		{
			return 'handle' ;
		}
		
		else if ( $Variable===null )
		{
			return 'null' ;
		}
		
		else 
		{
			return '??' ;
		}
	}
	
	/**
	 * 以严格的方式检查数组
	 * 
	 * @access	public
	 * @param	$arrArray	array	待检查的数组
	 * @param	$arrTypes	array	类型
	 * @static
	 * @return	void
	 */
	static public function CheckArray( $arrArray,array $arrTypes)
	{			
		if( !is_array($arrArray) )
		{
			return false ;
		}
			
		foreach( $arrArray as $Element)
		{
			$bRet = false ;
			foreach($arrTypes as $sType)
			{
				if( self::IsA($Element,$sType) )
				{
					$bRet = true ;
					break ;
				}
			}
			
			if(!$bRet)
			{
				return false ;
			}
		}
		
		return true ;
	}
	
	
	/**
	 * 判断变量 是否符合给定的类型
	 * 可以给入多种类型，变量只需符合其中之一。
	 * 如果类型 是 类名，则以 is_a（IsKindOf()函数） 判断
	 * 
	 * @access	public
	 * @param	$Variable	mixed			待检查的变量名
	 * @param	$arrTypes	string,array	必须符合的各项类型
	 * @static
	 * @return	void
	 */
	static public function IsThese($Variable,$Types)
	{
		if( !self::IsA($Types,'string') and !self::CheckArray($Types,array('string')) )
		{
			throw new JCAT_Exception( JCAT_Language::SentenceEx('参数 $Types 必须为 string 或 各项元素为string的数组','JCAT',null), JCAT_Exception::MakeExceptionCode(__CLASS__,9) ) ;
		}
		
		if( is_string( $Types ) )
		{
			$arrTypes = array($Types) ;
		}
		else
		{
			$arrTypes = $Types ;
		}
				
		
		// 类型检查
		foreach( $arrTypes as $sType )
		{
			if( self::IsA($Variable,$sType) )
			{
				return true ;
			}
		}
		
		return false ;
	}
	
	
	/**
	 * 将路径整理成统一的格式，斜线方向一致，清除路径中的 “..”、“.” 以及连续“/” ，并且目录统一用“/”（或“\”）结尾
	 * 
	 * @access	public
	 * @param	$sPath				string	路径
	 * @param	$bUnixStyle=true	bool	返回 Unix 路径风格
	 * @static
	 * @return	string
	 */
	static public function TidyPath ( $sPath,$bUnixStyle=true)
	{
		// 统一 斜线方向
		$sRetPath = str_replace('\\','/',$sPath) ;

		// 归并连续斜线
		$sRetPath = preg_replace('|/+|','/',$sRetPath) ;
		
		// 削除 .. 和  .
		$arrDirs = explode('/',$sRetPath) ;
		$arrDirs2 = array() ;
		//print_r($arrDirs) ;
		while( ($sDirName=array_shift($arrDirs))!==null )
		{
			if($sDirName=='.')
			{
				continue ;
			}
			if($sDirName=='..')
			{
				if( count($arrDirs2) )
				{
					array_pop($arrDirs2) ;
					continue ;
				}
			}
			
			array_push($arrDirs2,$sDirName) ;
		}
		$sRetPath = implode('/',$arrDirs2) ;
		//print_r($arrDirs2) ;
		
		// 目录 以  '/' 结尾
		
		// 存在的目录
		if( is_dir($sRetPath) )
		{
			if( !preg_match('|/$|',$sRetPath) )
			{
				$sRetPath.= '/' ;
			}
		}
		
		// 不存在，但是符合目录的格式
		else if( preg_match("|\.$|",$sPath) )
		{
			if( !preg_match('|/$|',$sRetPath) )
			{
				$sRetPath.= '/' ;
			}
		}
		
		

		// 还原 驱动器符号
		$sRetPath = str_replace(':/',':\\',$sRetPath) ;

		// 转换到 Windows 斜线风格
		if(!$bUnixStyle)
		{
			$sRetPath = str_replace('/','\\',$sRetPath) ;
		}

		return $sRetPath ;
	}
	
	
	/**
	 * 返回当前时间（微秒级）
	 * 
	 * @access	public
	 * @param	$bExact=true	bool	精确到 微秒，该参数false的话，等同 time()
	 * @static
	 * @return	float,int
	 */
	static public function Now ( $bExact=true )
	{
		if($bExact)
		{
			list($nMS,$nS) = explode(' ',microtime()) ;
			return $nS+$nMS ;
		}
		else
		{
			return time() ;
		}
	}
	
	/**
	 * 产生乱数字串
	 * 
	 * @access	public
	 * @param	$nLength		int			字串長度
	 * @param	$sCharBox=null	string,null	可用字符
	 * @static
	 * @return	string
	 */
	static public function RandString ( $nLength, $sCharBox=null )
	{
		if( $sCharBox===null )
		{
			$sBox = strtoupper(md5(self::Now(true) . rand(1000000000,9999999999))) ;
			$sBox.= md5(self::Now(true) . rand(1000000000,9999999999)) ;
		}
		else
		{
			$sBox = $sCharBox ;
		}
		
		$n = $nLength ;
		$nBoxEnd = strlen($sBox) - 1 ;
		$sRet = '' ;
		while($n--)
		{
			$sRet.= substr($sBox,rand(0,$nBoxEnd),1) ;
		}

		return $sRet ;
	}
	
	/**
	 * 动态地创建对象
	 * 
	 * @access	public
	 * @param	$sClassName		string	类名
	 * @param	$arrParams		array	参数
	 * @static
	 * @return	string
	 */
	static public function CreateObject ( $sClassName, array $arrParams=array() )
	{
		if( !class_exists($sClassName) )
		{
			throw new JCAT_Exception( JCAT_Language::SentenceEx('参数 $sClassName 必须是有效的类名。','JCAT',null), JCAT_Exception::MakeExceptionCode(__CLASS__,10) ) ;
		}
		
		$arrArgList = array() ;
		foreach($arrParams as $sKey=>$Item)
		{
			$arrArgList[] = "\$arrParams[$sKey]" ;
		}
		$sArgList = implode(', ',$arrArgList) ;
		
		return eval("return new $sClassName( {$sArgList} );") ;
	}
	
	
	
	
}

/*macro_exception_code:10*/
?>